Skip to content

Wrap custom html field labels in error class when showing in field validation messages#3049

Open
AbdiTolesa wants to merge 8 commits into
masterfrom
issue-6392
Open

Wrap custom html field labels in error class when showing in field validation messages#3049
AbdiTolesa wants to merge 8 commits into
masterfrom
issue-6392

Conversation

@AbdiTolesa
Copy link
Copy Markdown
Contributor

@AbdiTolesa AbdiTolesa commented Mar 27, 2026

Fix https://github.com/Strategy11/formidable-pro/issues/6392

Test procedure

  1. Enable AJAX submission in your form
  2. Add a field and set it to be required
  3. For the field label, use html that has a <div> tag in it. Eg. "Enter your answer
    < i >here< /i >
    "
  4. Preview the form and try submitting empty values
  5. Observe that there are validation errors printed
  6. Submit again (before reloading the page and clearing the previous errors)
  7. Confirm that the errors are not duplicated

Summary by CodeRabbit

  • Bug Fixes
    • Improved error message handling with consistent HTML formatting and sanitization for all field error displays.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 27, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR refactors error message handling in the form validation system by introducing a centralized getErrorHtml() function that consistently normalizes error markup for both plain text and pre-formatted HTML messages, replacing previous inline branching logic.

Changes

Error HTML Normalization

Layer / File(s) Summary
HTML Sanitization Utility
js/formidable.js
New purifyHtml() helper uses jQuery.parseHTML to safely parse HTML strings and reconstruct them through a temporary DOM element.
Centralized Error HTML Generation
js/formidable.js
Added getErrorHtml(errorMessage, id) function that normalizes error messages by wrapping plain text in div.frm_error and sanitizing pre-formatted HTML with conditional role="alert" based on frm_js.include_alert_role configuration.
Integration with Error Display
js/formidable.js
Updated addFieldError() to call getErrorHtml() instead of using inline branching logic to determine whether to wrap or sanitize error markup.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A helper here, a function there,
Error HTML handled with care—
No more branching cluttered the way,
Just getErrorHtml to save the day!
Clean and centered, the forms now shine,
Validation messages perfectly aligned. 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.16% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Wrap custom html field labels in error class when showing in field validation messages' accurately describes the main change: normalizing error markup generation to ensure custom HTML in field labels is properly wrapped with the error class.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-6392

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@deepsource-io
Copy link
Copy Markdown

deepsource-io Bot commented Mar 27, 2026

DeepSource Code Review

We reviewed changes in f42ed06...59605a4 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

Important

Some issues found as part of this review are outside of the diff in this pull request and aren't shown in the inline review comments due to GitHub's API limitations. You can see those issues on the DeepSource dashboard.

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
PHP May 7, 2026 6:45p.m. Review ↗
JavaScript May 7, 2026 6:45p.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@js/formidable.js`:
- Around line 1158-1162: The current code creates a temporary container
(tempDiv) and adds the frm_error class to that container but then uses
tempDiv.innerHTML, which returns only children and drops the wrapper and its
attributes; instead, parse the errorMessage into tempDiv, get the parsed node
(e.g., tempDiv.firstElementChild or firstChild), add the frm_error class (and
preserve any id) to that parsed node, and then set errorHtml from the parsed
node's outerHTML so the wrapper, class and id are preserved; reference tempDiv,
errorMessage, errorHtml and the parsed node (firstElementChild) when making the
change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: db707e86-b21a-4e3c-a630-1824cb7b2997

📥 Commits

Reviewing files that changed from the base of the PR and between 2d8b30e and 135b0b2.

📒 Files selected for processing (1)
  • js/formidable.js

Comment thread js/formidable.js Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
js/formidable.js (1)

1147-1155: ⚠️ Potential issue | 🟠 Major

Custom <div> errors still miss id/role, so aria-describedby can point to a non-existent node.

Line 1153 only adds frm_error on the parsed node. In this branch, the generated element still doesn’t receive the id from addFieldError (and ignores alert role), which breaks the accessibility linkage/cleanup path.

🐛 Proposed fix
 function getErrorHtml( errorMessage, id ) {
 	const roleString = frm_js.include_alert_role ? 'role="alert"' : '';

 	if ( ! errorMessage.startsWith( '<div' ) ) {
 		return `<div class="frm_error" ${ roleString } id="${ id }">${ errorMessage }</div>`;
 	}

 	const tempDiv = document.createElement( 'div' );
 	tempDiv.innerHTML = errorMessage;
-	tempDiv.firstChild.classList.add( 'frm_error' );
+	const existingWrapper = tempDiv.firstElementChild;
+	if ( existingWrapper ) {
+		existingWrapper.classList.add( 'frm_error' );
+		existingWrapper.id = id;
+		if ( frm_js.include_alert_role ) {
+			existingWrapper.setAttribute( 'role', 'alert' );
+		}
+	}

 	return tempDiv.innerHTML;
 }
#!/bin/bash
# Verify current helper behavior around parsed custom HTML error markup.
sed -n '1140,1195p' js/formidable.js

# Confirm parsed-div branch currently mutates firstChild and does not set id/role.
rg -n "getErrorHtml|startsWith\\( '<div' \\)|firstChild\\.classList|existingWrapper|setAttribute\\( 'role'|\\.id\\s*=\\s*id" js/formidable.js

# Verify aria-describedby and cleanup depend on error element id.
rg -n "aria-describedby|getErrorElementId|errorMessage\\.id|removeFieldError" js/formidable.js
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@js/formidable.js` around lines 1147 - 1155, The parsed-HTML branch fails to
apply the id and role attributes that addFieldError expects, breaking
aria-describedby and cleanup; in the function that builds error markup (the
branch that creates tempDiv and uses tempDiv.firstChild), after adding the
frm_error class to tempDiv.firstChild also set its id to the same id value and
apply the roleString (or setAttribute('role', ...)) so the parsed node gets the
same id/role as the non-parsed branch; update getErrorHtml/addFieldError related
logic to ensure tempDiv.firstChild receives id and roleString before returning
tempDiv.innerHTML.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@js/formidable.js`:
- Around line 1147-1155: The parsed-HTML branch fails to apply the id and role
attributes that addFieldError expects, breaking aria-describedby and cleanup; in
the function that builds error markup (the branch that creates tempDiv and uses
tempDiv.firstChild), after adding the frm_error class to tempDiv.firstChild also
set its id to the same id value and apply the roleString (or
setAttribute('role', ...)) so the parsed node gets the same id/role as the
non-parsed branch; update getErrorHtml/addFieldError related logic to ensure
tempDiv.firstChild receives id and roleString before returning
tempDiv.innerHTML.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 22574bc4-b215-4e7a-97ae-fbfa07460255

📥 Commits

Reviewing files that changed from the base of the PR and between f69f6b1 and f840fe9.

📒 Files selected for processing (1)
  • js/formidable.js

@AbdiTolesa AbdiTolesa changed the title Wrap custom html field labels in error class when not Wrap custom html field labels in error class when showing in field validation messages Mar 27, 2026
@AbdiTolesa AbdiTolesa requested a review from lauramekaj1 March 27, 2026 19:14
@truongwp truongwp self-assigned this May 5, 2026
@truongwp truongwp requested review from garretlaxton and removed request for lauramekaj1 May 5, 2026 17:42
Copy link
Copy Markdown

@garretlaxton garretlaxton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fix works great!

I do want to confirm that script tags should be allowed in the field labels though?

@truongwp
Copy link
Copy Markdown
Contributor

truongwp commented May 6, 2026

@garretlaxton No, it shouldn't be allowed in the label.

@garretlaxton
Copy link
Copy Markdown

@truongwp I am able to add a script tag to the label that runs when viewing the form, unless I have define( 'DISALLOW_UNFILTERED_HTML', true); set. This also happens in the main branch, so it's not something new with this PR.
image

@truongwp
Copy link
Copy Markdown
Contributor

truongwp commented May 6, 2026

@Crabcyborg Should we pass the label through wp_kses_post()?

@garretlaxton If that's an issue, we will fix it in a separate PR.

@Crabcyborg
Copy link
Copy Markdown
Contributor

@truongwp I think it should be fine. I don't expect that people are actually using scripts in field labels. I expect that people use descriptions or custom HTML if they do need to add scripts.

Just in case, I think a new hook would be nice. Like frm_filter_field_labels. We can default it to true, but in case someone is using scripts in labels, they could just add a __return_false to revert the behaviour.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants